using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using RaisingStudio.SmallBasicCompiler.Completion;
using RaisingStudio.SmallBasicCompiler.Expressions;

namespace RaisingStudio.SmallBasicCompiler.Statements
{
    public class ForStatement : Statement
    {
        public List<Statement> ForBody = new List<Statement>();
        public Expression InitialValue;
        public Expression FinalValue;
        public Expression StepValue;
        public TokenInfo Iterator;
        public TokenInfo ForToken;
        public TokenInfo ToToken;
        public TokenInfo StepToken;
        public TokenInfo EndForToken;
        public override void AddSymbols(SymbolTable symbolTable)
        {
            if (this.Iterator.Token != Token.Illegal)
            {
                symbolTable.AddVariable(this.Iterator);
                symbolTable.AddVariableInitialization(this.Iterator);
            }
            if (this.InitialValue != null)
            {
                this.InitialValue.AddSymbols(symbolTable);
            }
            if (this.FinalValue != null)
            {
                this.FinalValue.AddSymbols(symbolTable);
            }
            if (this.StepValue != null)
            {
                this.StepValue.AddSymbols(symbolTable);
            }
            foreach (Statement current in this.ForBody)
            {
                current.AddSymbols(symbolTable);
            }
        }
        public override void PrepareForEmit(CodeGenScope scope)
        {
            foreach (Statement current in this.ForBody)
            {
                current.PrepareForEmit(scope);
            }
        }
        public override void EmitIL(CodeGenScope scope)
        {
            this.InitialValue.EmitIL(scope);
            FieldInfo field = scope.Fields[this.Iterator.NormalizedText];
            scope.ILGenerator.Emit(OpCodes.Stsfld, field);
            Label label = scope.ILGenerator.DefineLabel();
            Label label2 = scope.ILGenerator.DefineLabel();
            Label label3 = scope.ILGenerator.DefineLabel();
            Label label4 = scope.ILGenerator.DefineLabel();
            scope.ILGenerator.MarkLabel(label2);
            scope.ILGenerator.Emit(OpCodes.Ldsfld, field);
            this.FinalValue.EmitIL(scope);
            if (this.StepValue != null)
            {
                this.StepValue.EmitIL(scope);
                scope.ILGenerator.Emit(OpCodes.Ldc_R8, 0.0);
                scope.ILGenerator.EmitCall(OpCodes.Call, scope.TypeInfoBag.NumberToPrimitive, null);
                scope.ILGenerator.EmitCall(OpCodes.Call, scope.TypeInfoBag.LessThan, null);
                scope.ILGenerator.EmitCall(OpCodes.Call, scope.TypeInfoBag.PrimitiveToBoolean, null);
                scope.ILGenerator.Emit(OpCodes.Brfalse, label4);
                scope.ILGenerator.EmitCall(OpCodes.Call, scope.TypeInfoBag.GreaterThanOrEqualTo, null);
                scope.ILGenerator.EmitCall(OpCodes.Call, scope.TypeInfoBag.PrimitiveToBoolean, null);
                scope.ILGenerator.Emit(OpCodes.Brfalse, label);
                scope.ILGenerator.Emit(OpCodes.Br, label3);
            }
            scope.ILGenerator.MarkLabel(label4);
            scope.ILGenerator.EmitCall(OpCodes.Call, scope.TypeInfoBag.LessThanOrEqualTo, null);
            scope.ILGenerator.EmitCall(OpCodes.Call, scope.TypeInfoBag.PrimitiveToBoolean, null);
            scope.ILGenerator.Emit(OpCodes.Brfalse, label);
            scope.ILGenerator.MarkLabel(label3);
            foreach (Statement current in this.ForBody)
            {
                current.EmitIL(scope);
            }
            scope.ILGenerator.Emit(OpCodes.Ldsfld, field);
            if (this.StepValue != null)
            {
                this.StepValue.EmitIL(scope);
            }
            else
            {
                scope.ILGenerator.Emit(OpCodes.Ldc_R8, 1.0);
                scope.ILGenerator.EmitCall(OpCodes.Call, scope.TypeInfoBag.NumberToPrimitive, null);
            }
            scope.ILGenerator.EmitCall(OpCodes.Call, scope.TypeInfoBag.Add, null);
            scope.ILGenerator.Emit(OpCodes.Stsfld, field);
            scope.ILGenerator.Emit(OpCodes.Br, label2);
            scope.ILGenerator.MarkLabel(label);
        }
        public override void PopulateCompletionItems(CompletionBag completionBag, int line, int column, bool globalScope)
        {
            if (base.StartToken.Line != line)
            {
                Statement statementContaining = Statement.GetStatementContaining(this.ForBody, line);
                CompletionHelper.FillKeywords(completionBag, new Token[]
				{
					Token.EndFor
				});
                if (statementContaining != null)
                {
                    statementContaining.PopulateCompletionItems(completionBag, line, column, false);
                }
                return;
            }
            if (column <= this.ForToken.EndColumn)
            {
                CompletionHelper.FillAllGlobalItems(completionBag, globalScope);
                return;
            }
            if (this.ToToken.Token == Token.Illegal || column < this.ToToken.EndColumn)
            {
                CompletionHelper.FillKeywords(completionBag, new Token[]
				{
					Token.To
				});
                CompletionHelper.FillExpressionItems(completionBag);
                return;
            }
            if (this.StepToken.Token == Token.Illegal || column < this.StepToken.EndColumn)
            {
                CompletionHelper.FillKeywords(completionBag, new Token[]
				{
					Token.Step
				});
                CompletionHelper.FillExpressionItems(completionBag);
                return;
            }
            CompletionHelper.FillExpressionItems(completionBag);
        }
        public override int GetIndentationLevel(int line)
        {
            if (line == this.ForToken.Line)
            {
                return 0;
            }
            if (this.EndForToken.Token != Token.Illegal && line == this.EndForToken.Line)
            {
                return 0;
            }
            Statement statementContaining = Statement.GetStatementContaining(this.ForBody, line);
            if (statementContaining != null)
            {
                return 1 + statementContaining.GetIndentationLevel(line);
            }
            return 1;
        }
        public override string ToString()
        {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.AppendFormat(CultureInfo.CurrentUICulture, "{0} {1} = {2} To {3}", new object[]
			{
				this.ForToken.Text, 
				this.Iterator.Text, 
				this.InitialValue, 
				this.FinalValue
			});
            if (this.StepToken.TokenType != TokenType.Illegal)
            {
                stringBuilder.AppendFormat(CultureInfo.CurrentUICulture, "{0} {1}", new object[]
				{
					this.StepToken.Text, 
					this.StepValue
				});
            }
            stringBuilder.AppendLine();
            foreach (Statement current in this.ForBody)
            {
                stringBuilder.AppendFormat(CultureInfo.CurrentUICulture, "  {0}", new object[]
				{
					current
				});
            }
            stringBuilder.AppendFormat(CultureInfo.CurrentUICulture, "{0}\r\n", new object[]
			{
				this.EndForToken.Text
			});
            return stringBuilder.ToString();
        }
    }
}
